/*
 * $Id: InputDialog.java,v 1.7 2003/06/01 11:21:50 znamenacek Exp $
 *
 * Copyright (c) Tomas Znamenacek
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

package net.sf.vofce.gui;

import net.sf.vofce.guts.Parser;
import net.sf.vofce.guts.Function;
import net.sf.vofce.guts.Operator;
import net.sf.vofce.guts.SyntaxError;
import net.sf.vofce.guts.UnknownOperator;
import net.sf.vofce.guts.InvalidNumber;
import net.sf.vofce.guts.UnbalancedBrackets;

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import java.awt.Insets;
import java.awt.event.WindowAdapter;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.ResourceBundle;

import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.ImageIcon;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;

/**
 * Function input dialog.
 * Lets the user input string representing the function, validates
 * the string using parser so that only valid input is accepted.
 *
 * @author Tomas Znamenacek
 */
public class InputDialog extends JDialog implements DocumentListener {

	/** Localised resource strings. */
	protected static ResourceBundle resources;

	//
	// GUI components
	//
	
	private JTextField input;
	private JPanel wrapper;
	private JLabel prompt;
	private JButton okButton;
	private JButton cancelButton;
	private JPanel buttonPanel;
	private JPanel inputPanel;

	private JLabel advice;

	protected boolean cancelled = true;

	/**
	 * Create the dialog, lay out GUI components.
	 */
	public InputDialog(Frame parent) {

		super(parent, true);
		
		wrapper =	new JPanel();
		inputPanel =	new JPanel();
		prompt =	new JLabel();
		input =		new JTextField();
		buttonPanel =	new JPanel();
		cancelButton =	new JButton(cancelAction);
		okButton =	new JButton(okAction);

		getContentPane().setLayout(new FlowLayout());

		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent evt) {
				closeDialog(evt);
			}
		});

		wrapper.setLayout(new BoxLayout(wrapper, BoxLayout.Y_AXIS));

		wrapper.setBorder(new EmptyBorder(new Insets(10, 10, 10, 10)));
		inputPanel.setBorder(new EmptyBorder(new Insets(1, 1, 10, 1)));
		prompt.setText("y=");
		inputPanel.add(prompt);

		input.setColumns(20);
		inputPanel.add(input);

		wrapper.add(inputPanel);
	
		JPanel notes = new JPanel();
		advice = new JLabel(resources.getString("advice.syntax"));
		notes.add(advice);
		notes.setBorder(new EmptyBorder(new Insets(0, 0, 10, 0)));
		wrapper.add(notes);

		buttonPanel.add(cancelButton);
		buttonPanel.add(okButton);
		wrapper.add(buttonPanel);

		getContentPane().add(wrapper);

		input.getDocument().addDocumentListener(this);

		pack();
		setSize(getPreferredSize());
		setResizable(false);
		
		Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
		setLocation((int) ((screenDim.width - getWidth()) / 2), (int) ((screenDim.height - getHeight()) / 2));
	}

	public Function show(Function f) {

		cancelled = false;

		if (f == null) {
			input.setText("");
			setTitle(resources.getString("input.add"));
		} else {
			input.setText(f.getUserView());
			setTitle(resources.getString("input.change"));
		}

		validateInput();
		
		pack();
		getRootPane().setDefaultButton(okButton);
		super.show();

		if (cancelled) { return f; } else {
			try {
				return new Function(input.getText());
			} catch (Exception e) {
				// can't happen
				return null;
			}
		}
	}
	
	//
	// Methods implementing DocumentListener
	// 

	public void insertUpdate(DocumentEvent e) {
		validateInput();
	}
	
	public void removeUpdate(DocumentEvent e) {
		validateInput();
	}
	
	public void changedUpdate(DocumentEvent e) {
		// Not needed
	}

	//
	// PRIVATE METHODS
	// 

	/** Validates the user input. */
	private void validateInput() {
	
		Parser parser = new Parser();

		try {
			Operator root = parser.buildTree(input.getText());
			advice.setText(resources.getString("advice.ok"));
			okButton.setEnabled(true);

		} catch (SyntaxError e) {

			advice.setText(resources.getString("advice.syntax"));
			okButton.setEnabled(false);

		} catch (UnknownOperator e) {

			advice.setText(resources.getString("advice.unknown"));
			okButton.setEnabled(false);

		} catch (InvalidNumber e) {

			advice.setText(resources.getString("advice.number"));
			okButton.setEnabled(false);

		} catch (UnbalancedBrackets e) {

			advice.setText(resources.getString("advice.brackets"));
			okButton.setEnabled(false);

		} catch (Exception e) {
			
			advice.setText(resources.getString("advice.syntax"));
			okButton.setEnabled(false);
		}
		
	}
	
	/** Closes the dialog. */
	private void closeDialog(WindowEvent evt) {
		cancelled = true;
		setVisible(false);
		dispose();
	}
	
	/** OK action. */
	private AbstractAction okAction = new AbstractAction(resources.getString("button.ok")) {
		public void actionPerformed(ActionEvent e) {
			cancelled = false;
			dispose();
		}
	};
	
	/** Cancel action. */
	private AbstractAction cancelAction = new AbstractAction(resources.getString("button.cancel")) {
		public void actionPerformed(ActionEvent e) {
			cancelled = true;
			dispose();
		}
	};

	/**
	 * Returns image associated with given resource id.
	 */
	private ImageIcon getIcon(String id) {

		return new ImageIcon(getClass().getResource("/" + id));
	}

	static {
		
		resources = ResourceBundle.getBundle("net.sf.vofce.gui.resources");
	}
}
